home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / io / ObjectStreamClass.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  44.5 KB  |  1,458 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)ObjectStreamClass.java    1.77 98/09/01
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. import java.security.MessageDigest;
  18. import java.security.NoSuchAlgorithmException;
  19. import java.security.DigestOutputStream;
  20. import java.security.AccessController;
  21. import java.security.PrivilegedAction;
  22.  
  23. import java.lang.reflect.AccessibleObject;
  24. import java.lang.reflect.Modifier;
  25. import java.lang.reflect.Field;
  26. import java.lang.reflect.Member;
  27. import java.lang.reflect.Method;
  28. import java.lang.reflect.Constructor;
  29.  
  30. import java.util.Arrays;
  31. import java.util.Comparator;
  32. import java.util.Iterator;
  33.  
  34. /**
  35.  * Serialization's descriptor for classes.
  36.  * It contains the name and serialVersionUID of the class.
  37.  * <br>
  38.  * The ObjectStreamClass for a specific class loaded in this Java VM can
  39.  * be found/created using the lookup method.<p>
  40.  * The algorithm to compute the SerialVersionUID is described in 
  41.  * <a href="http://java.sun.com/products/jdk/1.2/docs/guide/serialization/spec/class.doc4.html"> Object Serialization Specification, Section 4.4, Stream Unique Identifiers</a>.
  42.  *
  43.  * @author  Roger Riggs
  44.  * @version @(#)ObjectStreamClass.java    1.45 97/08/03
  45.  * @see ObjectStreamField
  46.  * @see <a href="http://java.sun.com/products/jdk/1.2/docs/guide/serialization/spec/class.doc.html"> Object Serialization Specification, Section 4, Class Descriptors</a>
  47.  * @since   JDK1.1
  48.  */
  49. public class ObjectStreamClass implements java.io.Serializable {
  50.  
  51.     /** 
  52.      * Find the descriptor for a class that can be serialized. 
  53.      * Creates an ObjectStreamClass instance if one does not exist 
  54.      * yet for class. Null is returned if the specified class does not 
  55.      * implement java.io.Serializable or java.io.Externalizable.
  56.      */
  57.     public static ObjectStreamClass lookup(Class cl)
  58.     {
  59.     ObjectStreamClass desc = lookupInternal(cl);
  60.     if (desc.isSerializable() || desc.isExternalizable())
  61.         return desc;
  62.     return null;
  63.     }
  64.     /*
  65.      * Find the class descriptor for the specified class.
  66.      * Package access only so it can be called from ObjectIn/OutStream.
  67.      */
  68.     static ObjectStreamClass lookupInternal(Class cl)
  69.     {
  70.     /* Synchronize on the hashtable so no two threads will do
  71.      * this at the same time.
  72.      */
  73.     ObjectStreamClass desc = null;
  74.     synchronized (descriptorFor) {
  75.         /* Find the matching descriptor if it already known */
  76.         desc = findDescriptorFor(cl);
  77.         if (desc != null) {
  78.         return desc;
  79.         }
  80.         
  81.         /* Check if it's serializable */
  82.         boolean serializable = Serializable.class.isAssignableFrom(cl);
  83.  
  84.         /* If the class is only Serializable,
  85.          * lookup the descriptor for the superclass.
  86.          */
  87.         ObjectStreamClass superdesc = null;
  88.         if (serializable) {
  89.         Class superclass = cl.getSuperclass();
  90.         if (superclass != null) 
  91.             superdesc = lookup(superclass);
  92.         }
  93.  
  94.         /* Check if its' externalizable.
  95.          * If it's Externalizable, clear the serializable flag.
  96.          * Only one or the other may be set in the protocol.
  97.          */
  98.         boolean externalizable = false;
  99.         if (serializable) {
  100.         externalizable = 
  101.             ((superdesc != null) && superdesc.isExternalizable()) ||
  102.             Externalizable.class.isAssignableFrom(cl);
  103.         if (externalizable) {
  104.             serializable = false;
  105.         }
  106.         }
  107.  
  108.         /* Create a new version descriptor,
  109.          * it put itself in the known table.
  110.          */
  111.         desc = new ObjectStreamClass(cl, superdesc,
  112.                       serializable, externalizable);
  113.     }
  114.     return desc;
  115.     }
  116.     
  117.     /**
  118.      * The name of the class described by this descriptor.
  119.      */
  120.     public String getName() {
  121.     return name;
  122.     }
  123.  
  124.     /**
  125.      * Return the serialVersionUID for this class.
  126.      * The serialVersionUID defines a set of classes all with the same name
  127.      * that have evolved from a common root class and agree to be serialized
  128.      * and deserialized using a common format.
  129.      * NonSerializable classes have a serialVersionUID of 0L.
  130.      */
  131.     public long getSerialVersionUID() {
  132.     return suid;
  133.     }
  134.  
  135.     /**
  136.      * Return the class in the local VM that this version is mapped to.
  137.      * Null is returned if there is no corresponding local class.
  138.      */
  139.     public Class forClass() {
  140.     return ofClass;
  141.     }
  142.  
  143.     /**
  144.      * Return an array of the fields of this serializable class.
  145.      * @return an array containing an element for each persistent
  146.      * field of this class. Returns an array of length zero if
  147.      * there are no fields.
  148.      * @since JDK1.2
  149.      */
  150.     public ObjectStreamField[] getFields() {
  151.         // Return a copy so the caller can't change the fields.
  152.     if (fields.length > 0) {
  153.         ObjectStreamField[] dup = new ObjectStreamField[fields.length];
  154.         System.arraycopy(fields, 0, dup, 0, fields.length);
  155.         return dup;
  156.     } else {
  157.         return fields;
  158.     }
  159.     }
  160.  
  161.     /* Avoid unnecessary allocations within package. */
  162.     final ObjectStreamField[] getFieldsNoCopy() {
  163.     return fields;
  164.     }
  165.  
  166.     /**
  167.      * Get the field of this class by name.
  168.      * @return The ObjectStreamField object of the named field or null if there
  169.      * is no such named field.
  170.      */
  171.     public ObjectStreamField getField(String name) {
  172.     ObjectStreamField searchKey = 
  173.         ObjectStreamField.constructSearchKey(name, Byte.TYPE);
  174.  
  175.     int index = -1;
  176.     if (objFields != fields.length) {
  177.         // perform binary search over primitive fields.
  178.         index = Arrays.binarySearch(fields, searchKey);
  179.     }
  180.  
  181.     if (index < 0 && objFields > 0) {
  182.         // perform binary search over object fields.
  183.         searchKey.setSearchKeyTypeString(true);
  184.         index = Arrays.binarySearch(fields, searchKey);
  185.     }
  186.     return (index < 0) ? null : fields[index];
  187.     }
  188.  
  189.  
  190.     /**
  191.      * Get the field of this class by name and fieldType.
  192.      * @return The ObjectStreamField object of the named field, type
  193.      *         or null if there is no such named field of fieldType.
  194.      */
  195.     ObjectStreamField getField(String name, Class fieldType) {
  196.     ObjectStreamField searchKey = 
  197.         ObjectStreamField.constructSearchKey(name, fieldType);
  198.     int index = Arrays.binarySearch(fields, searchKey);
  199.     return (index < 0) ? null : fields[index];
  200.     }
  201.  
  202.     /**
  203.      * Return a string describing this ObjectStreamClass.
  204.      */
  205.     public String toString() {
  206.     StringBuffer sb = new StringBuffer();
  207.  
  208.     sb.append(name);
  209.     sb.append(": static final long serialVersionUID = ");
  210.     sb.append(Long.toString(suid));
  211.     sb.append("L;");
  212.     return sb.toString();
  213.     }
  214.  
  215.     /*
  216.      * Create a new ObjectStreamClass from a loaded class.
  217.      * Don't call this directly, call lookup instead.
  218.      */
  219.     private ObjectStreamClass(final Class cl, ObjectStreamClass superdesc,
  220.                   boolean serial, boolean extern)
  221.     {
  222.     ofClass = cl;        /* created from this class */
  223.  
  224.     name = cl.getName();
  225.     superclass = superdesc;
  226.     serializable = serial;
  227.     externalizable = extern;
  228.  
  229.     /*
  230.      * Enter this class in the table of known descriptors.
  231.      * Otherwise, when the fields are read it may recurse
  232.      * trying to find the descriptor for itself.
  233.      */
  234.     insertDescriptorFor(this);
  235.  
  236.     if (!serializable || externalizable) {
  237.         fields = NO_FIELDS;
  238.     } else if (serializable) {
  239.         /* Ask for permission to override field access checks.
  240.          */
  241.         AccessController.doPrivileged(new PrivilegedAction() {
  242.         public Object run() {
  243.         
  244.             /* Fill in the list of persistent fields.
  245.              * If it is declared, use the declared serialPersistentFields.
  246.              * Otherwise, extract the fields from the class itself.
  247.              */
  248.             try {
  249.             Field pf = cl.getDeclaredField("serialPersistentFields");
  250.             pf.setAccessible(true);
  251.             ObjectStreamField[] f = (ObjectStreamField[])pf.get(cl);
  252.             int mods = pf.getModifiers();
  253.             //field must be private for security reasons.
  254.             if (Modifier.isPrivate(mods)) {
  255.                 fields = f;
  256.             }
  257.             } catch (NoSuchFieldException e) {
  258.             fields = null;
  259.             } catch (IllegalAccessException e) {
  260.             fields = null;
  261.             } catch (IllegalArgumentException e) {
  262.             fields = null;
  263.             }
  264.  
  265.             if (fields == null) {
  266.             /* Get all of the declared fields for this
  267.              * Class. setAccessible on all fields so they
  268.              * can be accessed later.  Create a temporary
  269.              * ObjectStreamField array to hold each
  270.              * non-static, non-transient field. Then copy the
  271.              * temporary array into an array of the correct
  272.              * size once the number of fields is known.
  273.              */
  274.             Field[] actualfields = cl.getDeclaredFields();
  275.             AccessibleObject.setAccessible(actualfields, true);
  276.  
  277.             int numFields = 0;
  278.             ObjectStreamField[] tempFields = 
  279.                 new ObjectStreamField[actualfields.length];
  280.             for (int i = 0; i < actualfields.length; i++) {
  281.                 int modifiers = actualfields[i].getModifiers();
  282.                 if (!Modifier.isStatic(modifiers) &&
  283.                 !Modifier.isTransient(modifiers)) {
  284.                 tempFields[numFields++] =
  285.                     new ObjectStreamField(actualfields[i]);
  286.                 }
  287.             }
  288.             fields = new ObjectStreamField[numFields];
  289.             System.arraycopy(tempFields, 0, fields, 0, numFields);
  290.             
  291.             } else {
  292.             // For each declared persistent field, look for an actual
  293.             // reflected Field. If there is one, make sure it's the correct
  294.             // type and cache it in the ObjectStreamClass for that field.
  295.             for (int j = fields.length-1; j >= 0; j--) {
  296.                 try {
  297.                 Field reflField = cl.getDeclaredField(fields[j].getName());
  298.                 if (fields[j].getType() == reflField.getType()) {
  299.                     reflField.setAccessible(true);
  300.                     fields[j].setField(reflField);
  301.                 } else {
  302.                     // TBD: Should this be flagged as an error?
  303.                 }
  304.                 } catch (NoSuchFieldException e) {
  305.                 // Nothing to do
  306.                 }
  307.             }
  308.             }
  309.             return null;
  310.         }
  311.         });
  312.  
  313.         if (fields.length > 1)
  314.         Arrays.sort(fields);
  315.  
  316.         /* Set up field data for use while writing using the API api. */
  317.         computeFieldInfo();
  318.     }
  319.  
  320.     /* Get the serialVersionUID from the class.
  321.      * It uses the access override mechanism so make sure
  322.      * the field objects is only used here.
  323.      *
  324.      * NonSerializable classes have a serialVerisonUID of 0L.
  325.      */
  326.     if (isNonSerializable()) {
  327.         suid = 0L;
  328.     } else {
  329.  
  330.         // Lookup special Serializable members using reflection.
  331.         AccessController.doPrivileged(new PrivilegedAction() {
  332.         public Object run() {
  333.             try {
  334.             Field f = cl.getDeclaredField("serialVersionUID");
  335.             int mods = f.getModifiers();
  336.             if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
  337.                 f.setAccessible(true);
  338.                 suid = f.getLong(cl);
  339.             } else {
  340.                 suid = computeSerialVersionUID(cl);
  341.             }
  342.             } catch (NoSuchFieldException ex) {
  343.             suid = computeSerialVersionUID(cl);
  344.             } catch (IllegalAccessException ex) {
  345.             suid = computeSerialVersionUID(cl);
  346.             }
  347.         
  348.             /* check for class provided substitution methods, 
  349.              * writeReplace and readResolve. Methods can not
  350.              * be static.
  351.              */
  352.             writeReplaceMethod = 
  353.             getDeclaredMethod("writeReplace", NULL_ARGS,
  354.                       0, Modifier.STATIC);
  355.             if (writeReplaceMethod == null && superclass != null &&
  356.             checkSuperMethodAccess(superclass.writeReplaceMethod)) {
  357.             writeReplaceMethod = superclass.writeReplaceMethod;
  358.             }
  359.         
  360.             readResolveMethod = 
  361.             getDeclaredMethod("readResolve", NULL_ARGS,
  362.                       0, Modifier.STATIC);
  363.             if (readResolveMethod == null && superclass != null &&
  364.             checkSuperMethodAccess(superclass.readResolveMethod)) {
  365.             readResolveMethod = superclass.readResolveMethod;
  366.             }
  367.         
  368.             /* Cache lookup of writeObject and readObject for 
  369.              * Serializable classes. (Do not lookup for Externalizable)
  370.              */
  371.             if (serializable) { 
  372.  
  373.             //Workaround compiler bug. See declaration for more detail.
  374.             if (OOS_ARGS == null || OIS_ARGS == null) {
  375.                 initStaticMethodArgs();
  376.             }
  377.             //end Workaround.
  378.             
  379.             writeObjectMethod = 
  380.                 getDeclaredMethod("writeObject", OOS_ARGS,
  381.                       Modifier.PRIVATE, Modifier.STATIC);
  382.             if (writeObjectMethod != null) {
  383.                 hasWriteObjectMethod = true;
  384.             }
  385.             readObjectMethod = 
  386.                 getDeclaredMethod("readObject", OIS_ARGS,
  387.                           Modifier.PRIVATE, Modifier.STATIC);
  388.             }
  389.             return null;
  390.         }
  391.         });
  392.     }
  393.     }
  394.  
  395.     /*
  396.      * Create an empty ObjectStreamClass for a class about to be read.
  397.      * This is separate from read so ObjectInputStream can assign the
  398.      * wire handle early, before any nested ObjectStreamClass might
  399.      * be read.
  400.      */
  401.     ObjectStreamClass(String n, long s) {
  402.     name = n;
  403.     suid = s;
  404.     superclass = null;
  405.     }
  406.  
  407.     /* Validate the compatibility of the stream class descriptor and 
  408.      * the specified local class.
  409.      *
  410.      * @exception InvalidClassException if stream and local class are 
  411.      *                                  not compatible.
  412.      */
  413.     private void validateLocalClass(Class localCl) throws InvalidClassException {
  414.     if (localClassDesc == null)
  415.         throw new InvalidClassException(localCl.getName(), 
  416.                         "Local class not compatible");
  417.  
  418.     if (suid != localClassDesc.suid) {
  419.  
  420.         /* Check for exceptional cases that allow mismatched suid. */
  421.  
  422.         /* Allow adding Serializable or Externalizable
  423.          * to a later release of the class. 
  424.          */
  425.         boolean addedSerialOrExtern = 
  426.         isNonSerializable() || localClassDesc.isNonSerializable();
  427.  
  428.         /* Disregard the suid of an array when name and localCl.Name differ. 
  429.          * If resolveClass() returns an array with a different package 
  430.          * name, the serialVersionUIDs will not match since the fully
  431.          * qualified array class is used in the
  432.          * computation of the array's serialVersionUID. There is
  433.          * no way to set a permanent serialVersionUID for an array type.
  434.          */
  435.         boolean arraySUID = (localCl.isArray() && ! localCl.getName().equals(name));
  436.  
  437.         if (! arraySUID && ! addedSerialOrExtern ) {
  438.         throw new InvalidClassException(localCl.getName(), 
  439.             "Local class not compatible:" + 
  440.             " stream classdesc serialVersionUID=" + suid +
  441.             " local class serialVersionUID=" + localClassDesc.suid);
  442.         }
  443.         
  444.     }
  445.  
  446.     /* compare the class names, stripping off package names. */
  447.     if (! compareClassNames(name, localCl.getName(), '.'))
  448.         throw new InvalidClassException(localCl.getName(),
  449.              "Incompatible local class name. " +
  450.                  "Expected class name compatible with " + 
  451.              name);
  452.  
  453.     /*
  454.      * Test that both implement either serializable or externalizable.
  455.      */
  456.     if ((serializable && localClassDesc.externalizable) ||
  457.         (externalizable && localClassDesc.serializable))
  458.         throw new InvalidClassException(localCl.getName(),
  459.                     "Serializable is incompatible with Externalizable");
  460.  
  461.     }
  462.  
  463.     /*
  464.      * Set the local class that this stream class descriptor matches.
  465.      * The base class name and serialization version id must match if
  466.      * both classes are serializable.
  467.      * Fill in the reflected Fields that will be used for reading.
  468.      */
  469.     void setClass(Class cl) throws InvalidClassException {
  470.  
  471.     /* Allow no local class implementation. Must be able to 
  472.      * skip objects in stream introduced by class evolution.
  473.      */
  474.     if (cl == null) {
  475.         localClassDesc = null;
  476.         ofClass = null;
  477.         computeFieldInfo();
  478.         return;
  479.     }
  480.  
  481.     localClassDesc = lookupInternal(cl);
  482.     validateLocalClass(cl);
  483.  
  484.     /* Disable instance deserialization when one class is serializable 
  485.      * and the other is not. */
  486.     if ((serializable != localClassDesc.serializable) ||
  487.         (externalizable != localClassDesc.externalizable)) {
  488.  
  489.         /* Delay signaling InvalidClassException until trying 
  490.              * to deserialize an instance of this class. Allows
  491.          * a previously nonSerialized class descriptor that was written 
  492.              * into the stream to be made Serializable
  493.          * or Externalizable, in a later release.
  494.          */
  495.         disableInstanceDeserialization = true;
  496.         ofClass = cl;
  497.         return;
  498.     }
  499.  
  500.     /* Set up the reflected Fields in the class where the value of each 
  501.      * field in this descriptor should be stored.
  502.      * Each field in this ObjectStreamClass (the source) is located (by 
  503.      * name) in the ObjectStreamClass of the class(the destination).
  504.      * In the usual (non-versioned case) the field is in both
  505.      * descriptors and the types match, so the reflected Field is copied.
  506.      * If the type does not match, a InvalidClass exception is thrown.
  507.      * If the field is not present in the class, the reflected Field 
  508.      * remains null so the field will be read but discarded.
  509.      * If extra fields are present in the class they are ignored. Their
  510.      * values will be set to the default value by the object allocator.
  511.      * Both the src and dest field list are sorted by type and name.
  512.      */
  513.  
  514.     ObjectStreamField[] destfield = 
  515.         (ObjectStreamField[])localClassDesc.fields;
  516.     ObjectStreamField[] srcfield = 
  517.         (ObjectStreamField[])fields;
  518.  
  519.     int j = 0;
  520.     nextsrc:
  521.     for (int i = 0; i < srcfield.length; i++ ) {
  522.         /* Find this field in the dest*/
  523.         for (int k = j; k < destfield.length; k++) {
  524.           if (srcfield[i].getName().equals(destfield[k].getName())) {
  525.           /* found match */
  526.           if (srcfield[i].isPrimitive() && 
  527.               !srcfield[i].typeEquals(destfield[k])) {
  528.               throw new InvalidClassException(cl.getName(),
  529.                           "The type of field " +
  530.                                destfield[i].getName() +
  531.                                " of class " + name +
  532.                                " is incompatible.");
  533.           }
  534.  
  535.           /* Skip over any fields in the dest that are not in the src */
  536.            j = k; 
  537.           
  538.           srcfield[i].setField(destfield[j].getField());
  539.           // go on to the next source field
  540.           continue nextsrc;
  541.           }
  542.         }
  543.     }
  544.  
  545.     /* Set up field data for use while reading from the input stream. */
  546.     computeFieldInfo();
  547.  
  548.     /* Remember the class this represents */
  549.     ofClass = cl;
  550.  
  551.     /* get the cache of these methods from the local class 
  552.      * implementation. 
  553.      */
  554.     readObjectMethod = localClassDesc.readObjectMethod;
  555.     readResolveMethod = localClassDesc.readResolveMethod;
  556.     }
  557.  
  558.     /* Compare the base class names of streamName and localName.
  559.      * 
  560.      * @return  Return true iff the base class name compare.
  561.      * @parameter streamName    Fully qualified class name.
  562.      * @parameter localName    Fully qualified class name.
  563.      * @parameter pkgSeparator    class names use either '.' or '/'.
  564.      * 
  565.      * Only compare base class name to allow package renaming.
  566.      */
  567.     static boolean compareClassNames(String streamName,
  568.                      String localName,
  569.                      char pkgSeparator) {
  570.     /* compare the class names, stripping off package names. */
  571.     int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
  572.     if (streamNameIndex < 0) 
  573.         streamNameIndex = 0;
  574.  
  575.     int localNameIndex = localName.lastIndexOf(pkgSeparator);
  576.     if (localNameIndex < 0)
  577.         localNameIndex = 0;
  578.  
  579.     return streamName.regionMatches(false, streamNameIndex, 
  580.                     localName, localNameIndex,
  581.                     streamName.length() - streamNameIndex);
  582.     }
  583.  
  584.     /*
  585.      * Compare the types of two class descriptors.
  586.      * They match if they have the same class name and suid
  587.      */
  588.     boolean typeEquals(ObjectStreamClass other) {
  589.     return (suid == other.suid) &&
  590.         compareClassNames(name, other.name, '.');
  591.     }
  592.     
  593.     /*
  594.      * Return the superclass descriptor of this descriptor.
  595.      */
  596.     void setSuperclass(ObjectStreamClass s) {
  597.     superclass = s;
  598.     }
  599.  
  600.     /*
  601.      * Return the superclass descriptor of this descriptor.
  602.      */
  603.     ObjectStreamClass getSuperclass() {
  604.     return superclass;
  605.     }
  606.     
  607.     /*
  608.      * Return whether the class has a writeObject method
  609.      */
  610.     boolean hasWriteObject() {
  611.     return hasWriteObjectMethod;
  612.     }
  613.     
  614.     /*
  615.      * Return true if all instances of 'this' Externalizable class 
  616.      * are written in block-data mode from the stream that 'this' was read
  617.      * from. <p>
  618.      *
  619.      * In JDK 1.1, all Externalizable instances are not written 
  620.      * in block-data mode.
  621.      * In JDK 1.2, all Externalizable instances, by default, are written
  622.      * in block-data mode and the Externalizable instance is terminated with
  623.      * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable 
  624.      * instances.
  625.      *
  626.      * IMPLEMENTATION NOTE:
  627.      *   This should have been a mode maintained per stream; however,
  628.      *   for compatibility reasons, it was only possible to record
  629.      *   this change per class. All Externalizable classes within
  630.      *   a given stream should either have this mode enabled or 
  631.      *   disabled. This is enforced by not allowing the PROTOCOL_VERSION
  632.      *   of a stream to he changed after any objects have been written.
  633.      *
  634.      * @see ObjectOuputStream#useProtocolVersion
  635.      * @see ObjectStreamConstants#PROTOCOL_VERSION_1
  636.      * @see ObjectStreamConstants#PROTOCOL_VERSION_2
  637.      *
  638.      * @since JDK 1.2
  639.      */
  640.     boolean hasExternalizableBlockDataMode() {
  641.     return hasExternalizableBlockData;
  642.     }
  643.  
  644.     /*
  645.      * Return the ObjectStreamClass of the local class this one is based on.
  646.      */
  647.     ObjectStreamClass localClassDescriptor() {
  648.     return localClassDesc;
  649.     }
  650.     
  651.     /*
  652.      * Get the Serializability of the class.
  653.      */
  654.     boolean isSerializable() {
  655.     return serializable;
  656.     }
  657.  
  658.     /*
  659.      * Get the externalizability of the class.
  660.      */
  661.     boolean isExternalizable() {
  662.     return externalizable;
  663.     }
  664.  
  665.     boolean isNonSerializable() {
  666.     return ! (externalizable || serializable);
  667.     }
  668.  
  669.     /*
  670.      * Calculate the size of the array needed to store primitive data and the
  671.      * number of object references to read when reading from the input 
  672.      * stream.
  673.      */
  674.     private void computeFieldInfo() {
  675.     primBytes = 0;
  676.     objFields = 0;
  677.  
  678.     for (int i = 0; i < fields.length; i++ ) {
  679.         switch (fields[i].getTypeCode()) {
  680.         case 'B':
  681.         case 'Z':
  682.             fields[i].setOffset(primBytes);
  683.             primBytes += 1;
  684.             break;
  685.         case 'C':
  686.         case 'S': 
  687.         fields[i].setOffset(primBytes);
  688.             primBytes += 2;
  689.             break;
  690.  
  691.         case 'I':
  692.         case 'F': 
  693.             fields[i].setOffset(primBytes);
  694.             primBytes += 4;
  695.             break;
  696.         case 'J':
  697.         case 'D' :
  698.         fields[i].setOffset(primBytes);
  699.             primBytes += 8;
  700.             break;
  701.         
  702.         case 'L':
  703.         case '[':
  704.             fields[i].setOffset(objFields);
  705.             objFields += 1;
  706.             break;
  707.         }
  708.     }
  709.     }
  710.     
  711.     /*
  712.      * Compute a hash for the specified class.  Incrementally add
  713.      * items to the hash accumulating in the digest stream.
  714.      * Fold the hash into a long.  Use the SHA secure hash function.
  715.      */
  716.     private static long computeSerialVersionUID(Class cl) {
  717.     ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  718.  
  719.     long h = 0;
  720.     try {
  721.         MessageDigest md = MessageDigest.getInstance("SHA");
  722.         DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  723.         DataOutputStream data = new DataOutputStream(mdo);
  724.  
  725.  
  726.         data.writeUTF(cl.getName());
  727.         
  728.         int classaccess = cl.getModifiers();
  729.         classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  730.                 Modifier.INTERFACE | Modifier.ABSTRACT);
  731.  
  732.         /* Workaround for javac bug that only set ABSTRACT for
  733.          * interfaces if the interface had some methods.
  734.          * The ABSTRACT bit reflects that the number of methods > 0.
  735.          * This is required so correct hashes can be computed
  736.          * for existing class files.
  737.          * Previously this hack was previously present in the VM.
  738.          */
  739.         Method[] method = cl.getDeclaredMethods();
  740.         if ((classaccess & Modifier.INTERFACE) != 0) {
  741.         classaccess &= (~Modifier.ABSTRACT);
  742.         if (method.length > 0) {
  743.             classaccess |= Modifier.ABSTRACT;
  744.         }
  745.         }
  746.  
  747.         data.writeInt(classaccess);
  748.  
  749.         /* 
  750.          * Get the list of interfaces supported,
  751.          * Accumulate their names in Lexical order
  752.          * and add them to the hash
  753.          */
  754.         if (!cl.isArray()) {
  755.         /* In JDK1.2fcs, getInterfaces() was modified to return
  756.          * {java.lang.Cloneable, java.io.Serializable} when
  757.          * called on array classes.  These values would upset
  758.          * the computation of the hash, so we explicitly omit
  759.          * them from its computation.
  760.          */
  761.         Class interfaces[] = cl.getInterfaces();
  762.         Arrays.sort(interfaces, compareClassByName);
  763.         
  764.         for (int i = 0; i < interfaces.length; i++) {
  765.             data.writeUTF(interfaces[i].getName());
  766.         }
  767.         }
  768.  
  769.         /* Sort the field names to get a deterministic order */
  770.         Field[] field = cl.getDeclaredFields();
  771.         Arrays.sort(field, compareMemberByName);
  772.  
  773.         for (int i = 0; i < field.length; i++) {
  774.         Field f = field[i];
  775.  
  776.         /* Include in the hash all fields except those that are
  777.          * private transient and private static.
  778.          */
  779.         int m = f.getModifiers();
  780.         if (Modifier.isPrivate(m) && 
  781.             (Modifier.isTransient(m) || Modifier.isStatic(m)))
  782.             continue;
  783.  
  784.         data.writeUTF(f.getName());
  785.         data.writeInt(m);
  786.         data.writeUTF(getSignature(f.getType()));
  787.         }
  788.  
  789.         if (hasStaticInitializer(cl)) {
  790.         data.writeUTF("<clinit>");
  791.         data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
  792.         data.writeUTF("()V");
  793.         }
  794.  
  795.         /*
  796.          * Get the list of constructors including name and signature
  797.          * Sort lexically, add all except the private constructors
  798.          * to the hash with their access flags
  799.          */
  800.  
  801.         MethodSignature[] constructors =
  802.         MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
  803.         for (int i = 0; i < constructors.length; i++) {
  804.         MethodSignature c = constructors[i];
  805.         String mname = "<init>";
  806.         String desc = c.signature;
  807.         desc = desc.replace('/', '.');
  808.         data.writeUTF(mname);
  809.         data.writeInt(c.member.getModifiers());
  810.         data.writeUTF(desc);
  811.         }
  812.  
  813.         /* Include in the hash all methods except those that are
  814.          * private transient and private static.
  815.          */
  816.         MethodSignature[] methods =
  817.         MethodSignature.removePrivateAndSort(method);
  818.         for (int i = 0; i < methods.length; i++ ) {
  819.         MethodSignature m = methods[i];    
  820.         String desc = m.signature;
  821.         desc = desc.replace('/', '.');
  822.         data.writeUTF(m.member.getName());
  823.         data.writeInt(m.member.getModifiers());
  824.         data.writeUTF(desc);
  825.         }
  826.  
  827.         /* Compute the hash value for this class.
  828.          * Use only the first 64 bits of the hash.
  829.          */
  830.         data.flush();
  831.         byte hasharray[] = md.digest();
  832.         for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  833.         h += (long)(hasharray[i] & 255) << (i * 8);
  834.         }
  835.     } catch (IOException ignore) {
  836.         /* can't happen, but be deterministic anyway. */
  837.         h = -1;
  838.     } catch (NoSuchAlgorithmException complain) {
  839.         throw new SecurityException(complain.getMessage());
  840.     }
  841.     return h;
  842.     }
  843.  
  844.  
  845.     /**
  846.       * Compute the JVM signature for the class.
  847.       */
  848.     static String getSignature(Class clazz) {
  849.     String type = null;
  850.     if (clazz.isArray()) {
  851.         Class cl = clazz;
  852.         int dimensions = 0;
  853.         while (cl.isArray()) {
  854.         dimensions++;
  855.         cl = cl.getComponentType();
  856.         }
  857.         StringBuffer sb = new StringBuffer();
  858.         for (int i = 0; i < dimensions; i++) {
  859.         sb.append("[");
  860.         }
  861.         sb.append(getSignature(cl));
  862.         type = sb.toString();
  863.     } else if (clazz.isPrimitive()) {
  864.         if (clazz == Integer.TYPE) {
  865.         type = "I";
  866.         } else if (clazz == Byte.TYPE) {
  867.         type = "B";
  868.         } else if (clazz == Long.TYPE) {
  869.         type = "J";
  870.         } else if (clazz == Float.TYPE) {
  871.         type = "F";
  872.         } else if (clazz == Double.TYPE) {
  873.         type = "D";
  874.         } else if (clazz == Short.TYPE) {
  875.         type = "S";
  876.         } else if (clazz == Character.TYPE) {
  877.         type = "C";
  878.         } else if (clazz == Boolean.TYPE) {
  879.         type = "Z";
  880.         } else if (clazz == Void.TYPE) {
  881.         type = "V";
  882.         }
  883.     } else {
  884.         type = "L" + clazz.getName().replace('.', '/') + ";";
  885.     }
  886.     return type;
  887.     }
  888.  
  889.     /*
  890.      * Compute the JVM method descriptor for the method.
  891.      */
  892.     static String getSignature(Method meth) {
  893.     StringBuffer sb = new StringBuffer();
  894.  
  895.     sb.append("(");
  896.  
  897.     Class[] params = meth.getParameterTypes(); // avoid clone
  898.     for (int j = 0; j < params.length; j++) {
  899.         sb.append(getSignature(params[j]));
  900.     }
  901.     sb.append(")");
  902.     sb.append(getSignature(meth.getReturnType()));
  903.     return sb.toString();
  904.     }
  905.  
  906.     /*
  907.      * Compute the JVM constructor descriptor for the constructor.
  908.      */
  909.     static String getSignature(Constructor cons) {
  910.     StringBuffer sb = new StringBuffer();
  911.  
  912.     sb.append("(");
  913.  
  914.     Class[] params = cons.getParameterTypes(); // avoid clone
  915.     for (int j = 0; j < params.length; j++) {
  916.         sb.append(getSignature(params[j]));
  917.     }
  918.     sb.append(")V");
  919.     return sb.toString();
  920.     }
  921.  
  922.  
  923.     /*
  924.      * locate the ObjectStreamClass for this class and write it to the stream.
  925.      *
  926.      * @serialData
  927.      *  <code>primitive UTF-8 String</code>  Qalified class name.
  928.      *  <code>long</code>  Serial version unique identifier for compatible classes.
  929.      *    <code>byte</code>. Mask with <code>java.io.ObjectStreamConstants.SC_*</code>.<br>
  930.      *    <code>short</code>. Number of Serializable fields to follow. If 0, no more data.
  931.      *  <code>list of Serializable Field descriptors</code>. Descriptors for Primitive 
  932.      *       typed fields are written first sorted by field name 
  933.      *       followed by descriptors for the object typed fields sorted 
  934.      *       by field name. The names are sorted using String.compareTo.
  935.      *
  936.      *  A Serializable field consists of the following data:
  937.      *   <code>byte</code>  TypeCode of field. See ObjectStreamField.getTypeCode().
  938.      *   <code>primitive UTF-8 encoded String</code>  Unqualified name of field.
  939.      *   <code>String</code>   Qualified class name. 
  940.      */
  941.     void write(ObjectOutputStream s) throws IOException {
  942.     
  943.     /* write the flag indicating that this class has write/read object methods */
  944.     int flags = 0;
  945.     if (hasWriteObjectMethod)
  946.         flags |= ObjectStreamConstants.SC_WRITE_METHOD;
  947.     if (serializable)
  948.         flags |= ObjectStreamConstants.SC_SERIALIZABLE;
  949.     if (externalizable) {
  950.         flags |=  ObjectStreamConstants.SC_EXTERNALIZABLE;
  951.  
  952.         /* Enabling the SC_BLOCK_DATA flag indicates PROTCOL_VERSION_2.*/
  953.         if (! s.useDeprecatedExternalizableFormat)
  954.         flags |= ObjectStreamConstants.SC_BLOCK_DATA;
  955.         }
  956.     s.writeByte(flags);
  957.     
  958.     // If there are no fields, write a null and return
  959.     if (fields == null) {
  960.         s.writeShort(0);
  961.         return;
  962.     }
  963.  
  964.     /* write the total number of fields */
  965.     s.writeShort(fields.length);
  966.     
  967.     /* Write out the descriptors of the primitive fields Each
  968.      * descriptor consists of the UTF fieldname, a short for the
  969.      * access modes, and the first byte of the signature byte.
  970.      * For the object types, ('[' and 'L'), a reference to the
  971.      * type of the field follows.
  972.      */
  973.     for (int i = 0; i < fields.length; i++ ) {
  974.         ObjectStreamField f = fields[i];
  975.         s.writeByte(f.getTypeCode());
  976.         s.writeUTF(f.getName());
  977.         if (!f.isPrimitive()) {
  978.         s.writeTypeString(f.getTypeString());
  979.         }
  980.     }
  981.     }
  982.  
  983.     /*
  984.      * Read the version descriptor from the stream.
  985.      * Write the count of field descriptors
  986.      * for each descriptor write the first character of its type,
  987.      * the name of the field.
  988.      * If the type is for an object either array or object, write
  989.      * the type typedescriptor for the type
  990.      */
  991.     void read(ObjectInputStream s) throws IOException, ClassNotFoundException {
  992.     
  993.     /* read flags and determine whether the source class had
  994.          * write/read methods.
  995.      */
  996.     byte flags = s.readByte();
  997.     serializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
  998.     externalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
  999.     hasWriteObjectMethod = serializable ?
  1000.         (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0 :
  1001.         false;
  1002.     hasExternalizableBlockData = externalizable ? 
  1003.         (flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0 :
  1004.         false;
  1005.                      
  1006.  
  1007.     /* Read the number of fields described.
  1008.      * For each field read the type byte, the name.
  1009.      */    
  1010.     int count = s.readShort();
  1011.     fields = new ObjectStreamField[count];
  1012.  
  1013.     /* disable replacement of String objects read
  1014.      * by ObjectStreamClass. */
  1015.     boolean prevEnableResolve = s.enableResolve;
  1016.     s.enableResolve = false;
  1017.     try {
  1018.         for (int i = 0; i < count; i++ ) {
  1019.         char type = (char)s.readByte();
  1020.         String name = s.readUTF();
  1021.         String ftype = null;
  1022.         if (type == '[' || type == 'L') {
  1023.             ftype = (String)s.readObject();
  1024.         }
  1025.         fields[i] = 
  1026.             new ObjectStreamField(name, type, null, ftype);
  1027.         }
  1028.     } finally {
  1029.         s.enableResolve = prevEnableResolve;
  1030.     }
  1031.     }
  1032.  
  1033.     /* To accomodate nonSerializable classes written into a stream,
  1034.      * this check must be delayed until an instance is deserialized.
  1035.      */
  1036.     void verifyInstanceDeserialization() throws InvalidClassException {
  1037.     if (disableInstanceDeserialization) {
  1038.         String name = (serializable || externalizable) ? 
  1039.                         localClassDesc.getName() : getName();
  1040.         String stype = (serializable || localClassDesc.serializable) ? 
  1041.                           "Serializable" : "Externalizable";
  1042.         throw new InvalidClassException(name, "is not " + stype);
  1043.     }
  1044.     }
  1045.  
  1046.     /*
  1047.      * Cache of Class -> ClassDescriptor Mappings.
  1048.      */
  1049.     static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  1050.  
  1051.     /*
  1052.      * findDescriptorFor a Class.  This looks in the cache for a
  1053.      * mapping from Class -> ObjectStreamClass mappings.  The hashCode
  1054.      * of the Class is used for the lookup since the Class is the key.
  1055.      * The entries are extended from java.lang.ref.SoftReference so the
  1056.      * gc will be able to free them if needed.
  1057.      */
  1058.     private static ObjectStreamClass findDescriptorFor(Class cl) {
  1059.  
  1060.     int hash = cl.hashCode();
  1061.     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1062.     ObjectStreamClassEntry e;
  1063.     ObjectStreamClassEntry prev;
  1064.     
  1065.     /* Free any initial entries whose refs have been cleared */
  1066.     while ((e = descriptorFor[index]) != null && e.get() == null) {
  1067.         descriptorFor[index] = e.next;
  1068.     }
  1069.  
  1070.     /* Traverse the chain looking for a descriptor with ofClass == cl.
  1071.      * unlink entries that are unresolved.
  1072.      */
  1073.     prev = e;
  1074.     while (e != null ) {
  1075.         ObjectStreamClass desc = (ObjectStreamClass)(e.get());
  1076.         if (desc == null) {
  1077.         // This entry has been cleared,  unlink it
  1078.         prev.next = e.next;
  1079.         } else {
  1080.         if (desc.ofClass == cl)
  1081.             return desc;
  1082.         prev = e;
  1083.         }
  1084.         e = e.next;
  1085.     }
  1086.     return null;
  1087.     }
  1088.  
  1089.     /*
  1090.      * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  1091.      */
  1092.     private static void insertDescriptorFor(ObjectStreamClass desc) {
  1093.     // Make sure not already present
  1094.     if (findDescriptorFor(desc.ofClass) != null) {
  1095.         return;
  1096.     }
  1097.  
  1098.     int hash = desc.ofClass.hashCode();
  1099.     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1100.     ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  1101.     e.next = descriptorFor[index];
  1102.            descriptorFor[index] = e;
  1103.     }
  1104.  
  1105.     /*
  1106.      * The name of this descriptor
  1107.      */
  1108.     private String name;
  1109.     
  1110.     /*
  1111.      * The descriptor of the supertype.
  1112.      */
  1113.     private ObjectStreamClass superclass;
  1114.  
  1115.     /*
  1116.      * Flags for Serializable and Externalizable.
  1117.      */
  1118.     private boolean serializable;
  1119.     private boolean externalizable;
  1120.     
  1121.     /*
  1122.      * Array of persistent fields of this class, sorted by
  1123.      * type and name.
  1124.      */
  1125.     private ObjectStreamField[] fields;
  1126.     
  1127.     /*
  1128.      * Class that is a descriptor for in this virtual machine.
  1129.      */
  1130.     private Class ofClass;
  1131.     
  1132.     /* 
  1133.      * SerialVersionUID for this class.
  1134.      */
  1135.     private long suid;
  1136.     
  1137.     /*
  1138.      * The total number of bytes of primitive fields.
  1139.      * The total number of object fields.
  1140.      */
  1141.     int primBytes;
  1142.     int objFields;
  1143.  
  1144.     /* True if this class has/had a writeObject method */
  1145.     private boolean hasWriteObjectMethod;
  1146.  
  1147.     /* In JDK 1.1, external data was not written in block mode.
  1148.      * As of JDK 1.2, external data is written in block data mode. This
  1149.      * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
  1150.      *
  1151.      * @since JDK 1.2
  1152.      */
  1153.     private boolean hasExternalizableBlockData;
  1154.     Method writeObjectMethod;
  1155.     Method readObjectMethod;
  1156.     Method readResolveMethod;
  1157.     Method writeReplaceMethod;
  1158.  
  1159.     /*
  1160.      * ObjectStreamClass that this one was built from.
  1161.      */
  1162.     private ObjectStreamClass localClassDesc;
  1163.     
  1164.     /* Indicates that stream and local class are not both
  1165.      * serializable. No instances of this class can be deserialized.
  1166.      */
  1167.     private boolean disableInstanceDeserialization = false;
  1168.  
  1169.     /* Find out if the class has a static class initializer <clinit> */
  1170.     private static native boolean hasStaticInitializer(Class cl);
  1171.  
  1172.     /** use serialVersionUID from JDK 1.1. for interoperability */
  1173.     private static final long serialVersionUID = -6120832682080437368L;
  1174.  
  1175.     /**
  1176.      * Set serialPersistentFields of a Serializable class to this value to 
  1177.      * denote that the class has no Serializable fields. 
  1178.      */
  1179.     public static final ObjectStreamField[] NO_FIELDS = 
  1180.     new ObjectStreamField[0];
  1181.  
  1182.     /**
  1183.      * Class ObjectStreamClass is special cased within the 
  1184.      * Serialization Stream Protocol. 
  1185.      *
  1186.      * An ObjectStreamClass is written intially into an ObjectOutputStream 
  1187.      * in the following format:
  1188.      * <pre>
  1189.      *      TC_CLASSDESC className, serialVersionUID, flags, 
  1190.      *                   length, list of field descriptions.
  1191.      *
  1192.      * FIELDNAME        TYPES
  1193.      *                  DESCRIPTION
  1194.      * --------------------------------------
  1195.      * className        primitive data String
  1196.      *                  Fully qualified class name.
  1197.      *
  1198.      * serialVersionUID long
  1199.      *                  Stream Unique Identifier for compatible classes
  1200.      *                  with same base class name.
  1201.      *
  1202.      * flags            byte
  1203.      *                  Attribute bit fields defined in 
  1204.      *                  <code>java.io.ObjectStreamConstants.SC_*</code>.
  1205.      *
  1206.      * length           short
  1207.      *                  The number of field descriptions to follow.
  1208.      *
  1209.      * fieldDescription (byte, primitive data String, String Object)
  1210.      *                  A pseudo-externalized format of class
  1211.      *                  <code>java.io.ObjectStreamField</code>.
  1212.      *                  Consists of typeCode, fieldName, and,
  1213.      *                  if a nonPrimitive typecode, a fully qualified
  1214.      *                  class name. See <code>Class.getName</code> method 
  1215.      *                  for the typecode byte encodings.
  1216.      * </pre>
  1217.      * The first time the class descriptor
  1218.      * is written into the stream, a new handle is generated.
  1219.      * Future references to the class descriptor are
  1220.      * written as references to the initial class descriptor instance.
  1221.      *
  1222.      * @see java.io.ObjectOutputStream#writeUTF(java.lang.String)
  1223.      */
  1224.     private static final ObjectStreamField[] serialPersistentFields = 
  1225.     NO_FIELDS;
  1226.  
  1227.     /*
  1228.      * Entries held in the Cache of known ObjectStreamClass objects.
  1229.      * Entries are chained together with the same hash value (modulo array size).
  1230.      */
  1231.     private static class ObjectStreamClassEntry extends java.lang.ref.SoftReference
  1232.     {
  1233.     ObjectStreamClassEntry(ObjectStreamClass c) {
  1234.         super(c);
  1235.     }
  1236.     ObjectStreamClassEntry next;
  1237.     }
  1238.  
  1239.     /*
  1240.      * Comparator object for Classes and Interfaces
  1241.      */
  1242.     private static Comparator compareClassByName =
  1243.         new CompareClassByName();
  1244.  
  1245.     private static class CompareClassByName implements Comparator {
  1246.     public int compare(Object o1, Object o2) {
  1247.         Class c1 = (Class)o1;
  1248.         Class c2 = (Class)o2;
  1249.         return (c1.getName()).compareTo(c2.getName());
  1250.     }
  1251.     }
  1252.  
  1253.     /*
  1254.      * Comparator object for Members, Fields, and Methods
  1255.      */
  1256.     private static Comparator compareMemberByName =
  1257.         new CompareMemberByName();
  1258.  
  1259.     private static class CompareMemberByName implements Comparator {
  1260.     public int compare(Object o1, Object o2) {
  1261.         String s1 = ((Member)o1).getName();
  1262.         String s2 = ((Member)o2).getName();
  1263.  
  1264.         if (o1 instanceof Method) {
  1265.         s1 += getSignature((Method)o1);
  1266.         s2 += getSignature((Method)o2);
  1267.         } else if (o1 instanceof Constructor) {
  1268.         s1 += getSignature((Constructor)o1);
  1269.         s2 += getSignature((Constructor)o2);
  1270.         }
  1271.         return s1.compareTo(s2);
  1272.     }
  1273.     }
  1274.  
  1275.     /* It is expensive to recompute a method or constructor signature
  1276.        many times, so compute it only once using this data structure. */
  1277.     private static class MethodSignature implements Comparator {
  1278.     Member member;
  1279.     String signature;      // cached parameter signature
  1280.  
  1281.     /* Given an array of Method or Constructor members,
  1282.        return a sorted array of the non-private members.*/
  1283.     /* A better implementation would be to implement the returned data
  1284.        structure as an insertion sorted link list.*/
  1285.     static MethodSignature[] removePrivateAndSort(Member[] m) {
  1286.         int numNonPrivate = 0;
  1287.         for (int i = 0; i < m.length; i++) {
  1288.         if (! Modifier.isPrivate(m[i].getModifiers())) {
  1289.             numNonPrivate++;
  1290.         }
  1291.         }
  1292.         MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1293.         int cmi = 0;
  1294.         for (int i = 0; i < m.length; i++) {
  1295.         if (! Modifier.isPrivate(m[i].getModifiers())) {
  1296.             cm[cmi] = new MethodSignature(m[i]);
  1297.             cmi++;
  1298.         }
  1299.         }
  1300.         if (cmi > 0)
  1301.         Arrays.sort(cm, cm[0]);
  1302.         return cm;
  1303.     }
  1304.  
  1305.     /* Assumes that o1 and o2 are either both methods
  1306.        or both constructors.*/
  1307.     public int compare(Object o1, Object o2) {
  1308.         /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1309.         if (o1 == o2)
  1310.         return 0;
  1311.         
  1312.         MethodSignature c1 = (MethodSignature)o1;
  1313.         MethodSignature c2 = (MethodSignature)o2;
  1314.  
  1315.         int result;
  1316.         if (isConstructor()) {
  1317.         result = c1.signature.compareTo(c2.signature);
  1318.         } else { // is a Method.
  1319.         result = c1.member.getName().compareTo(c2.member.getName());
  1320.         if (result == 0)
  1321.             result = c1.signature.compareTo(c2.signature);
  1322.         }
  1323.         return result;
  1324.     }
  1325.  
  1326.     private boolean isConstructor() {
  1327.         return member instanceof Constructor;
  1328.     }
  1329.  
  1330.     private MethodSignature(Member m) {
  1331.         member = m;
  1332.         if (isConstructor()) {
  1333.         signature = ObjectStreamClass.getSignature((Constructor)m);
  1334.         } else {
  1335.         signature = ObjectStreamClass.getSignature((Method)m);
  1336.         }
  1337.     }
  1338.     }
  1339.  
  1340.     boolean isResolvable() {
  1341.     return readResolveMethod != null;
  1342.     }
  1343.  
  1344.     boolean isReplaceable() {
  1345.     return writeReplaceMethod != null;
  1346.     }
  1347.  
  1348.     static Object invokeMethod(Method method, Object obj, Object[] args)
  1349.     throws IOException
  1350.     {
  1351.     Object returnValue = null;
  1352.     try {
  1353.         returnValue = method.invoke(obj, args);
  1354.     } catch (java.lang.reflect.InvocationTargetException e) {
  1355.         Throwable t = e.getTargetException();
  1356.         if (t instanceof IOException)
  1357.         throw (IOException)t;
  1358.         else if (t instanceof RuntimeException)
  1359.         throw (RuntimeException) t;
  1360.         else if (t instanceof Error)
  1361.         throw (Error) t;
  1362.         else
  1363.         throw new Error("interal error");
  1364.     } catch (IllegalAccessException e) {
  1365.         // cannot happen
  1366.         throw new Error("interal error");
  1367.     }
  1368.     return returnValue;
  1369.     }
  1370.  
  1371.     /* ASSUMPTION: Called within priviledged access block. 
  1372.      *             Needed to set declared methods and to set the
  1373.      *             accessibility bit.
  1374.      */
  1375.     private Method getDeclaredMethod(String methodName, Class[] args, 
  1376.                      int requiredModifierMask,
  1377.                      int disallowedModifierMask) {
  1378.     Method method = null;
  1379.     try {
  1380.         method = 
  1381.         ofClass.getDeclaredMethod(methodName, args);
  1382.         if (method != null) {
  1383.         int mods = method.getModifiers();
  1384.         if ((mods & disallowedModifierMask) != 0 ||
  1385.             (mods & requiredModifierMask) != requiredModifierMask) {
  1386.             method = null;
  1387.         } else {
  1388.             method.setAccessible(true);
  1389.         }
  1390.         }
  1391.     } catch (NoSuchMethodException e) {
  1392.         // Since it is alright if methodName does not exist,
  1393.         // no need to do anything special here.
  1394.     }
  1395.     return method;
  1396.     }
  1397.  
  1398.     /*
  1399.      * Return true if scMethod is accessible from the context of 
  1400.      * this ObjectStreamClass' local implementation class.
  1401.      * Simulate java accessibility rules of accessing method 'scMethod' 
  1402.      * from a method within subclass this.forClass.
  1403.      * If method would not be accessible, returns null. 
  1404.      *
  1405.      * @param scMethod  A method from the superclass of this ObjectStreamClass.
  1406.      */
  1407.     private boolean checkSuperMethodAccess(Method scMethod) {
  1408.     if (scMethod == null) {
  1409.         return false;
  1410.     }
  1411.     
  1412.     int supermods =  scMethod.getModifiers();
  1413.     if (Modifier.isPublic(supermods) || Modifier.isProtected(supermods)) {
  1414.         return true;
  1415.     } else if (Modifier.isPrivate(supermods)) {
  1416.         return false;
  1417.     } else {
  1418.         // check package-private access.
  1419.         return isSameClassPackage(scMethod.getDeclaringClass(), ofClass);
  1420.     }
  1421.     }
  1422.  
  1423.     /* Will not work for array classes. */
  1424.     static private boolean isSameClassPackage(Class cl1, Class cl2) {
  1425.     if (cl1.getClassLoader() != cl2.getClassLoader()) {
  1426.         return false;
  1427.     } else {
  1428.         String clName1 = cl1.getName();
  1429.         String clName2 = cl2.getName();
  1430.         int idx1 = clName1.lastIndexOf('.');
  1431.         int idx2 = clName2.lastIndexOf('.');
  1432.         if (idx1 == -1 || idx2 == -1) {
  1433.         /* One of the two doesn't have a package. Only return true
  1434.          * if the other one also does not have a package.
  1435.          */
  1436.         return idx1 == idx2;
  1437.         } else {
  1438.         return clName1.regionMatches(false, 0, 
  1439.                          clName2, 0, idx1 - 1);
  1440.         }
  1441.     }
  1442.     }
  1443.  
  1444.     private final static Class[] NULL_ARGS = {};
  1445.     
  1446.     //WORKAROUND compiler bug with following code.
  1447.     //static final Class[] OIS_ARGS = {ObjectInpuStream.class};
  1448.     //static final Class[] OOS_ARGS = {ObjectOutpuStream.class};
  1449.     private static Class[] OIS_ARGS = null;
  1450.     private static Class[] OOS_ARGS = null;
  1451.     private static void initStaticMethodArgs() {
  1452.     OOS_ARGS = new Class[1];
  1453.     OOS_ARGS[0] = ObjectOutputStream.class;
  1454.     OIS_ARGS = new Class[1];
  1455.     OIS_ARGS[0] = ObjectInputStream.class;
  1456.     }
  1457. }
  1458.